package org.scalacn.easyscala.interpreter;

import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.URL;


public class ScalaInterpreter implements Interpreter {

	  public ScalaInterpreter() {
		  init();
	  }
	  private ByteArrayOutputStream interpOutStream;

	  private scala.tools.nsc.Interpreter interp;
	  

		@Override
		public void init() {
			printMemory("before init");
		    String rtJarPath = getJarFromResource(getClass().getResource(
	        "/java/lang/Object.class"));
	    String scalaLibPath = getJarFromResource(getClass().getResource(
	        "/scala/Array.class"));
	    
	    interpOutStream = new ByteArrayOutputStream();

	    scala.tools.nsc.Settings settings = new scala.tools.nsc.Settings();
	    String codebasePath = rtJarPath + " " + scalaLibPath;

	    settings.Xcodebase().value_$eq(codebasePath.toString());
	    settings.classpath().value_$eq("");
	    settings.bootclasspath().value_$eq("");
	    settings.outdir().value_$eq(".");
	    settings.extdirs().value_$eq("");
	    interp = new scala.tools.nsc.Interpreter(settings, new PrintWriter(
	        new OutputStreamWriter(interpOutStream))) {
	      @Override
	      public ClassLoader parentClassLoader() {
	        return Thread.currentThread().getContextClassLoader();
	      }
	    };
	    printMemory("after init");
		}

	private void printMemory(String msg){
		long freeMemory = Runtime.getRuntime().freeMemory();
		long totalMemory = Runtime.getRuntime().totalMemory();
		long maxMemory = Runtime.getRuntime().maxMemory();
 
		long memoryUsed = totalMemory-freeMemory;
		
		System.out.println("maxMemory: " + maxMemory/1024/1024+"M");
		System.out.println(msg + " memoryUsed: " + memoryUsed/1024/1024+"M");
	}
	  
	@Override
	  public Context createContext() {
	    return new Ctx();
	  }

	@Override
	public String execute(String script) throws Exception {
		printMemory("ScalaInterpreter>execute>before execute");
		
	    StringBuffer strBuffer = new StringBuffer();
	    //interp.reset();
	    interp.reporter().reset();
	    interpOutStream.reset();

	    PrintStream output = new PrintStream(interpOutStream);
	    // We set System.out and System.err such that we capture anything
	    // that runs during interpretation (Such as a System.out.println
	    // call). The _only_ reason this doesn't fail due to concurrency,
	    // is because we don't get concurrent requests to a single JVM.
	    PrintStream out = System.out;
	    PrintStream err = System.err;
	    System.setOut(output);
	    System.setErr(output);

	    String end = "";
	    try {
	      // Eval the user text
	      //Boolean compiled = interp.compileString(script);
	      //System.out.println(compiled);
	    interp.interpret(script);
	    //System.out.println(results.toString());
	    //interp.reporter().printMessage(end);
	    } catch(Exception e){
	    	e.printStackTrace();
	    }finally {
	      System.setOut(out);
	      System.setErr(err);
	    }

	    output.flush();

	    strBuffer.append(new String(interpOutStream.toByteArray(), "UTF-8")); 
	    printMemory("ScalaInterpreter>execute>after execute");
	    return strBuffer.toString();
	}

	  /**
	   * Returns a URL to a Jar file in which a resource from that Jar file is
	   * located. This is the easiest way that we can locate certain Jar files.
	   */
	  private static String getJarFromResource(URL resource) {
	    String path = resource.toString();
	    int indexOfFile = path.indexOf("file:");
	    int indexOfSeparator = path.lastIndexOf('!');
	    return path.substring(indexOfFile, indexOfSeparator);
	  }

	  // NB: not serializable
	  static class Ctx implements Context {
	  }
	  
}
